package com.fast.fast.common.core.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定义线程池配置类
 * 要避免直接使用异常方法处理注解（@EnableAsync和@Async），这回导致无限创建线程数和队列数引发OOM问题
 * 请使用 @Async（"executor"）
 *
 * @author lyf
 * @date 2022/01/01 00:00 周六
 **/
@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolTaskExecutorConfig implements AsyncConfigurer {

    /**
     * 获取当前机器的核数, 不一定准确 请根据实际场景 CPU密集 || IO 密集
     */
    public static final int CPU_NUM = Runtime.getRuntime().availableProcessors();

    @Value("${thread.pool.corePoolSize:}")
    private Optional<Integer> corePoolSize;

    @Value("${thread.pool.maxPoolSize:}")
    private Optional<Integer> maxPoolSize;

    @Value("${thread.pool.keepAlive:}")
    private Optional<Integer> keepAlive;

    @Value("${thread.pool.queueCapacity:}")
    private Optional<Integer> queueCapacity;

    @Value("${thread.pool.awaitTerminationSeconds:}")
    private Optional<Integer> awaitTerminationSeconds;

    @Primary
    @Override
    @Bean("exe")
    public Executor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程大小 默认区 CPU 数量
        taskExecutor.setCorePoolSize(corePoolSize.orElse(CPU_NUM));
        // 最大线程大小 默认区 CPU * 2 数量
        taskExecutor.setMaxPoolSize(maxPoolSize.orElse(CPU_NUM * 2));
        // 最大存活时间 默认60秒
        taskExecutor.setKeepAliveSeconds(queueCapacity.orElse(60));
        // 队列最大容量，默认500
        taskExecutor.setQueueCapacity(queueCapacity.orElse(500));
        // 拒绝策略，直接丢弃任务
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(awaitTerminationSeconds.orElse(60));
        taskExecutor.setThreadNamePrefix("Fast-Common-Thread-");
        taskExecutor.initialize();
        return taskExecutor;
    }

    /**
     * 异步任务中异常处理
     * 无法被@RestControllerAdvice注解获取异常
     *
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (Throwable ex, Method method, Object... params) -> {
            log.info("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
            log.info("type        : " + ex.getClass().getName());
            log.info("exception   : " + ex.getMessage());
        };
    }

}
